﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.IO;
using System.Threading;
using System.Collections.ObjectModel;

namespace MMOG
{
    static class Client
    {
        public static bool[] KeyStatus = new bool[256];

        public static bool connected = false;
        public static bool exited = false;

        public static ClientInterface gui;
        public static GameInterface3d gameGUI;
        public static LoginForm loginForm;
        public static GameChooser gameChooser;
        public static LobbyForm lobbyForm;
        public static TcpClient client;
        public static StreamWriter writer;
        public static StreamReader reader;
        public static bool playGame = false;

        public static Chessboard3d board;

        public static int PORT = 29889;

        public static int FramePerSec = 0;
        public static int gameTime = 0;

        public static string Username = null;

        public static Collection<String> messageBuffer;
        public static Collection<RoomInfo> roomList;
        public static Collection<RoomControl> roomControlList;

        public static void listUpdate(String message)
        {
            Information info = new Information(message);
            String type = info.getString("type");
            String name = info.getString("name");
            if (type.Equals("add") && (!gui.friendList.Items.Contains(name)))
                gui.friendList.Items.Add(name);
            if (type.Equals("remove") && (gui.friendList.Items.Contains(name)))
                gui.friendList.Items.Remove(name);
        }

        public static void updateRoom(String message)
        {
            Information info = new Information(message);
            switch (info.getInt("id"))
            {
                case Information.RESET_ROOM:
                    for (int i = 0; i < roomControlList.Count; i++)
                        lobbyForm.splitContainer1.Panel2.Controls.Remove(roomControlList[i]);
                    roomControlList.Clear();
                    roomList.Clear();
                    break;
                case Information.ROOM_UPDATE:
                    int id = info.getInt("gameid");
                    String name = info.getString("name");
                    int nPlayer = info.getInt("nPlayer");
                    String password = info.getString("password");
                    RoomInfo roomInfo = new RoomInfo(id, name, password, nPlayer, 2, 0);
                    roomList.Add(roomInfo);
                    if ((!lobbyForm.onlyShowAvailable.Checked) || (nPlayer < 2))
                    {
                        RoomControl control = new RoomControl();
                        int pos = roomControlList.Count();
                        int itemPerRow = (lobbyForm.Width - 26) / 250;
                        int posx = (pos % itemPerRow) * 250;
                        int posy = (pos / itemPerRow) * 115;
                        control.Location = new System.Drawing.Point(posx, posy);
                        control.Size = new System.Drawing.Size(258, 117);
                        if (nPlayer < 2)
                            control.player2Icon.Visible = false;
                        else
                            control.joinButton.Visible = false;
                        control.idLabel.Text = "Room: " + id;
                        control.nameLabel.Text = name;
                        if (password.CompareTo("") == 0)
                            control.lockIcon.Visible = false;
                        lobbyForm.splitContainer1.Panel2.Controls.Add(control);
                        roomControlList.Add(control);
                    }
                    break;
            }
        }

        public static bool processMessages()
        {
            try
            {
                String message;
                lock (messageBuffer)
                {
                    if (messageBuffer.Count > 0)
                    {
                        message = messageBuffer[0];
                        messageBuffer.RemoveAt(0);
                    }
                    else return true;
                }
                gui.chatHistory.AppendText("Msg: " + message + "\n");
                Information info = new Information(message);
                int type = info.getInt("id");
                switch (type)
                {
                    case Information.CHAT_MESSAGE:
                        gui.chatHistory.AppendText(info.getString("message") + "\n");
                        break;
                    case Information.LIST_UPDATE:
                        listUpdate(message);
                        break;
                    case Information.POPUP_MESSAGE:
                        MessageBox.Show(info.getString("message"));
                        break;
                    case Information.KICK_MESSAGE:
                        MessageBox.Show(info.getString("message"));
                        exited = true;
                        break;
                    case Information.ROOM_UPDATE:
                        updateRoom(message);
                        break;
                    case Information.RESET_ROOM:
                        updateRoom(message);
                        break;
                }
                return true;
            }
            catch (Exception)
            {
                return false;
            }
        }

        public static void peekMessages()
        {
            try
            {
                while (true)
                {
                    String message = reader.ReadLine();
                    if (message == null)
                    {
                        exited = true;
                        return;
                    }
                    messageBuffer.Add(message);
                }
            }
            catch (Exception)
            {
                Client.exited = true;
            }
        }

        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            //
            gameGUI = new GameInterface3d();
            //gameGUI.Show();          

            Object3d obj = new Object3d();
            if (!obj.loadObj("piece.obj")) return;
            Object3d obj2 = new Object3d();
            if (!obj2.loadObj("chessboard.obj")) return;

            try
            {
                lobbyForm = new LobbyForm();
                lobbyForm.Hide();

                //Display login form and request authorization
                loginForm = new LoginForm();
                loginForm.Show();

                while (!connected)
                {
                    Application.DoEvents();
                    if (exited) return;
                    Thread.Sleep(10);
                }

                //Dispose login form
                loginForm.Hide();
                loginForm = null;

                //Init data
                messageBuffer = new Collection<string>();
                roomList = new Collection<RoomInfo>();
                roomControlList = new Collection<RoomControl>();
                Thread msgThread = new Thread(new ThreadStart(Client.peekMessages));
                msgThread.Start();

                //Init game list
                gameChooser = new GameChooser();
                gameChooser.gameList.Items.Add("Chinese Chess (3D) - Not available");
                gameChooser.gameList.Items.Add("Ultra Versus  - Not available");
                gameChooser.gameList.SelectedIndex = 0;

                //Display chat panel
                gui = new ClientInterface();
                gui.accountLabel.Text = Username;
                gui.Show();

                reader.DiscardBufferedData();

                board = new Chessboard3d(gameGUI.glControl);
                //playGame = true;
                while (!exited)
                {
                    Application.DoEvents();
                    processMessages();
                    //Thread.Sleep(3);

                    if (playGame)
                    {
                        board.draw();
                    }
                }
            }
            catch (Exception)
            {
            }
            finally
            {
                if (writer != null) writer.Close();
                if (reader != null) reader.Close();
                if (client != null) client.Close();
            }
        }
    }
}
